1 //-------------------------------------------------------------------------------------------------
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // Implements No Release Allocator.
7 //-------------------------------------------------------------------------------------------------
12 //to track nrlsalloc locations, #define NRLSTRACK
13 // set NRLSTRACK_GETSTACKS to 1 to track NRLSAllocations and the call stacks. Uses lots of mem: very expensive
15 //#define NRLSTRACK DEBUG && !defined( VBDBGEE ) && !defined(NDEBUG) && !defined(BUILDING_VBC) && !defined(BUILDING_VB7TO8)
16 //#define NRLSTRACK_GETSTACKS NRLSTRACK
20 // we're tracking allocations.
23 using namespace stdext
;
25 // we're tracking allocations.
30 long nHeapTotalAllocs
;
33 long nNrlsTotalAllocs
;
37 class NrlsAllocTracker
47 long AddAllocator(NorlsAllocator
*pAllocator
);
49 void RemoveAllocator(NorlsAllocator
*pAllocator
);
51 CComBSTR
GetAllocatorStatusReport(_Out_
long *pnCnt
, _Out_
long *pnTotMem
);
52 VBMemoryInUse
& GetVBMemoryStats(_In_ LPCSTR strDesc
);
56 typedef std::list
<NorlsAllocator
*> listNorls
;
60 VBMemoryInUse m_VBMemoryInUse
;
64 extern NrlsAllocTracker
*g_NrlsAllocTracker
;
65 #if NRLSTRACK_GETSTACKS
67 void * m_ptrNextBlock
; // linked list of allocations: point to prior one
68 size_t m_size
; // size of the nrls data
69 void * m_data
; // ptr to the actual NRLS data
71 #endif NRLSTRACK_GETSTACKS
77 // Holds a page of memory being used by the NorlsAllocator.
84 NorlsPage
* next
; // next page in use.
85 BYTE
* firstAvail
; // first available byte for allocation.
86 BYTE
* limitAvail
; // limit for allocation.
89 size_t sentinalEnd
; // Buffer overflow check
96 friend class NorlsAllocator
;
98 NorlsPage
* page
; // page.
99 BYTE
* nextFree
; // first free location within the page.
103 long m_nTotalAllocatedAtMark
;
104 #if NRLSTRACK_GETSTACKS
105 NrlsHeapData
* m_pLastBlockAtMark
; // ptr to linked list of alloc'd Heap blocks so VSAssert CHeapSpy can watch Nrlsallocs
106 #endif NRLSTRACK_GETSTACKS
113 #define NORLSLOC __WFILE__, __LINE__
120 friend class NrlsAllocTracker
;
127 NorlsAllocator
* heap
;
128 bool alreadyInAllowingWrite
;
130 AllowingWrite(NorlsAllocator
* heap
)
135 alreadyInAllowingWrite
= heap
->inAllowingWrite
;
136 heap
->inAllowingWrite
= true;
140 alreadyInAllowingWrite
= false;
145 if (!alreadyInAllowingWrite
&& heap
)
147 heap
->inAllowingWrite
= false;
150 bool OwnsHeapWriteability()
152 return !alreadyInAllowingWrite
;
160 _In_ WCHAR
*szFile
, _In_
long nLineNo
169 _In_ WCHAR
*szFile
, _In_
long nLineNo
,
173 _In_ PageHeap
& heapToAllocateFrom
176 PageHeap
& GetPageHeap()
181 void ForbidWrite(void * p
, size_t sz
)
184 ForbidWriteInternal(p
, sz
);
186 void AllowWrite(void * p
, size_t sz
)
189 AllowWriteInternal(p
, sz
);
192 void DisallowReadOnlyDirectives()
195 DisallowReadOnlyDirectivesInternal();
197 void AllowReadOnlyDirectives()
200 AllowReadOnlyDirectivesInternal();
202 bool AllowingReadOnlyDirectives()
205 return AllowingReadOnlyDirectivesInternal();
207 void MakeCurrentPageReadOnly()
210 MakeCurrentPageReadOnlyInternal();
211 } // Calling Alloc makes it writeable until the next call to MakeReadOnly
212 void MakeCurrentPageWriteable()
215 MakeCurrentPageWriteableInternal();
216 } // Calling Alloc makes it writeable until the next call to MakeReadOnly
217 void MakeAllHeapReadOnly()
220 MakeAllHeapReadOnlyInternal();
222 void MakeAllHeapWriteable()
225 MakeAllHeapWriteableInternal();
228 bool IsAddressInCurrentPage (const void * addr
) const;
229 bool IsAddressInHeap (const void * addr
) const
231 for (NorlsPage
* page
= pageList
; page
; page
= page
->next
)
233 if (addr
>= page
&& addr
< page
->limitAvail
)
239 void* AllocNonZero(size_t sz
);
240 void* Alloc(size_t sz
);
241 template <typename T
>
244 return (T
*)Alloc(sizeof(T
));
246 template <typename T
>
247 T
* _fastcall
AllocArray(size_t count
)
249 return (T
*)Alloc(VBMath::Multiply(sizeof(T
),count
));
253 _In_bytecount_(cbSizeOld
) void* pv
,
254 _In_
size_t cbSizeOld
,
255 _In_
size_t cbSizeNew
);
258 PWSTR
AllocStr(PCWSTR str
);
260 void Mark(NorlsMark
* mark
);
261 void Free(NorlsMark
* mark
);
263 size_t CalcCommittedSize () const;
264 const WCHAR
* GetDebugIdentifier() const;
268 DWORD m_dwCreatedThreadId
; // the thread on which this allocator was created
269 DWORD m_dwAllocThreadId
;// the thread on which allocations are occuring
270 long m_nSerialNo
; // the allocator's serialno
271 long m_nSeqNo
; /// the sequence # of the allocation for this allcoator
272 ULONG m_nTotalAllocated
;
273 #if NRLSTRACK_GETSTACKS
274 NrlsHeapData
* m_pLastBlock
; // ptr to linked list of alloc'd Heap blocks so VSAssert CHeapSpy can watch Nrlsallocs
275 HANDLE
TrackingHeapToUse();
276 static HANDLE g_nraSymbolHeap
;
278 #endif NRLSTRACK_GETSTACKS
284 NorlsAllocator(const NorlsAllocator
&);
285 NorlsAllocator
& operator=(const NorlsAllocator
&);
287 void Init(ProtectedEntityFlagsEnum entity
);
288 void VerifyHeapEntity()
290 VSASSERT(entity
, "Heap entity must be set before manipulating heap writeability");
293 void ForbidWriteInternal(void * p
, size_t sz
);
294 void AllowWriteInternal(void * p
, size_t sz
);
296 //allocates memory but doesn't clear it.
297 //'sz' [in/out] returns the true allocation size
298 void* _AllocNonZero(size_t& sz
);
300 void DisallowReadOnlyDirectivesInternal()
302 allowReadOnlyDirectives
= false;
304 void AllowReadOnlyDirectivesInternal()
306 allowReadOnlyDirectives
= true;
308 bool AllowingReadOnlyDirectivesInternal()
310 return allowReadOnlyDirectives
;
312 void MakeCurrentPageReadOnlyInternal(); // Calling Alloc makes it writeable until the next call to MakeReadOnly
313 void MakeCurrentPageWriteableInternal(); // Calling Alloc makes it writeable until the next call to MakeReadOnly
314 void MakeAllHeapReadOnlyInternal();
315 void MakeAllHeapWriteableInternal();
317 void SetPageWriteStatus(NorlsPage
* page
, bool writeable
);
318 void SetPageRegionWriteStatus(NorlsPage
* first
, NorlsPage
* last
, bool writeable
);
319 void SetAllPagesWriteStatus(bool writeable
);
321 BYTE
* nextFree
; // location of free area
322 BYTE
* limitFree
; // just beyond end of free area in this page.
324 NorlsPage
* pageList
; // list of pages used by this allocator.
325 NorlsPage
* pageLast
; // last page in the list.
327 // The source of pages for this heap.
328 PageHeap
& m_heapPage
;
331 void AllocNewPage(size_t sz
);
332 NorlsPage
* NewPage(size_t sz
);
334 ProtectedEntityFlagsEnum entity
;
335 bool allowReadOnlyDirectives
;
336 bool anyPageMarkedReadOnly
;
337 bool inAllowingWrite
;
340 inline size_t DebugSize (size_t sz
) const
343 if (!(sz
< sz
+ 1 + sizeof(size_t) + sizeof(void*) + sizeof(void*)))
345 VSASSERT(sz
< sz
+ 1 + sizeof(size_t) + sizeof(void*) + sizeof(void*), "Invalid");
348 return VBMath::RoundUpAllocSize(sizeof(size_t)) + VBMath::RoundUpAllocSize(sz
+ 1); // int at beginning for size, plus 1 (or more) bytes of sentinel.
350 static const BYTE DEBUGSENTINAL
= 0xAE; // put at end of block to detect overrun.
357 NRHeapMarker(NorlsAllocator
* h
)
367 NorlsAllocator
* heap
;
371 class NRHeapWriteMaker
374 NRHeapWriteMaker(NorlsAllocator
* heap
) : allowingWrite(heap
)
379 heap
->MakeAllHeapWriteable();
384 if (heap
&& allowingWrite
.OwnsHeapWriteability())
386 heap
->AllowReadOnlyDirectives();
387 heap
->MakeAllHeapReadOnly();
391 NorlsAllocator
* heap
;
392 NorlsAllocator::AllowingWrite allowingWrite
;
395 class NRHeapWriteAllower
398 NRHeapWriteAllower(NorlsAllocator
* heap
) : allowingWrite(heap
)
403 heap
->DisallowReadOnlyDirectives();
406 ~NRHeapWriteAllower()
408 if (heap
&& allowingWrite
.OwnsHeapWriteability())
410 heap
->AllowReadOnlyDirectives();
411 heap
->MakeAllHeapReadOnly();
415 NorlsAllocator
* heap
;
416 NorlsAllocator::AllowingWrite allowingWrite
;